package com.example.demo_mysql_mybatisplus.util.auditLog;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.example.demo_mysql_mybatisplus.util.api.crudFree.FreeUtil;
import com.example.demo_mysql_mybatisplus.util.auditLog.dto.AuditLogParamEntity;
import com.example.demo_mysql_mybatisplus.util.auditLog.dto.DiffParser;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.net.URLDecoder;
import java.util.Enumeration;
import java.util.Map;

@Slf4j
@Aspect
@Component
public class FreeAuditLogAop {


//    @Autowired
//    private RabbitTemplate rabbitTemplate;
//
//    @Autowired
//    private AuditLogService auditLogService;

    @Pointcut(value = "@annotation(com.example.demo_mysql_mybatisplus.util.auditLog.FreeAuditLog)")
    private void cutLog() {
    }

    @AfterReturning("cutLog()&&@annotation(freeAuditLog)")
    public void deal(JoinPoint joinPoint, FreeAuditLog freeAuditLog) throws Throwable {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        Enumeration<String> headerNane = request.getHeaders("MDZY_LOG_HEADER_NANE"); // 入口标志

        AuditLogParamEntity auditLogParamEntity = null;
        if (ObjectUtil.isNotEmpty(headerNane) && headerNane.hasMoreElements()) {
            String str = headerNane.nextElement();
            String operateInfo = URLDecoder.decode(str, "UTF-8");
            JSONObject userJson = JSONObject.parseObject(operateInfo);
            auditLogParamEntity = JSON.toJavaObject(userJson, AuditLogParamEntity.class);
        }
        if (ObjectUtil.isEmpty(auditLogParamEntity) ) {
            return;
        }
        try {
            Object requestBodyObj = FreeUtil.getRequestBodyObjInAOP( joinPoint);
            if(null!=requestBodyObj){
                Object rawValueTmp = BeanUtil.getFieldValue(requestBodyObj,"rawValue");
                Object newValueTmp = BeanUtil.getFieldValue(requestBodyObj,"newValue");

                String rawValue = rawValueTmp==null?"":rawValueTmp.toString();
                String newValue = newValueTmp==null?"":newValueTmp.toString();

                if(freeAuditLog.value() == AuditStrategyEnum.recordLogAndDealDifference){
                    recordAndDealDifference( rawValue , newValue, auditLogParamEntity);
                }else{
                    onlyRecordLog( rawValue , newValue, auditLogParamEntity);
                }
            }
        } catch (Exception e) {
            log.error("生成审计日志：发送mq消息异常", e);
        }
    }

    private void onlyRecordLog(String rawValue ,String newValue,AuditLogParamEntity auditLogParamEntity){
        if (!StrUtil.equals(newValue,rawValue)) {
            JSONObject reactantJSON = new JSONObject();
            reactantJSON.put("newValue", newValue);
            reactantJSON.put("oldValue", rawValue);

            JSONObject reactionEquationJSON = new JSONObject();
            reactionEquationJSON.put("data", reactantJSON);

            String diffJsonStr = JSON.toJSONString(reactionEquationJSON);

            initLogAndSend( auditLogParamEntity, rawValue, newValue, diffJsonStr);
        }
    }

    private void recordAndDealDifference(String rawValue ,String newValue,AuditLogParamEntity auditLogParamEntity){
        if (!StrUtil.equals(newValue,rawValue)) {
            //有新值，没旧值 ：旧值设置成对应的 空字符串
            if (ObjectUtil.isNotEmpty(newValue) && ObjectUtil.isEmpty(rawValue)) {
                Map mapObj = JSONObject.parseObject(newValue, Map.class);
                JSONObject rawJsonObject = new JSONObject();
                for (Object map : mapObj.entrySet()) {
                    rawJsonObject.put(((Map.Entry) map).getKey().toString(), "");
                }
                rawValue = rawJsonObject.toJSONString();
            }
            //没新值，有旧值 ：新值设置成对应的 空字符串
            if (ObjectUtil.isEmpty(newValue) && ObjectUtil.isNotEmpty(rawValue)) {
                Map mapObj = JSONObject.parseObject(rawValue, Map.class);
                JSONObject newJsonObject = new JSONObject();
                for (Object map : mapObj.entrySet()) {
                    newJsonObject.put(((Map.Entry) map).getKey().toString(), "");
                }
                newValue = newJsonObject.toJSONString();
            }
            //有新值，有旧值 ：获取差异信息
            String diffJsonStr  = "";
            if (ObjectUtil.isNotEmpty(newValue) && ObjectUtil.isNotEmpty(rawValue)) {
                JSONObject diffs = DiffParser.parseValueDiff(newValue, rawValue);
                diffJsonStr = diffs.toJSONString();
            }

            initLogAndSend( auditLogParamEntity, rawValue, newValue, diffJsonStr);
        }
    }

    private void initLogAndSend(AuditLogParamEntity auditLogParamEntity,String rawValue,String newValue,String diffJsonStr){

//        SysAuditLog auditLog = auditLogService.initLog(auditLogParamEntity.getBSystem(), auditLogParamEntity.getBModule(), auditLogParamEntity.getBOperationType(),
//                1, 0L, "", newValue, rawValue, diffJsonStr, "", "", 0L, 0L,
//                auditLogParamEntity.getBId(), auditLogParamEntity.getBName(), auditLogParamEntity.getBContent(), auditLogParamEntity.getIsHistory(), "");
//
//        rabbitTemplate.convertAndSend(ExchangeEnum.ELN_AUDIT_EXCHANGE.getExchangeName(),
//                QueueEnum.ELN_AUDIT_QUEUE.getRoutingKey(), auditLog);
    }

}

